/*********************************************************************************
 *      Copyright:  (C) 2019 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  main.c
 *    Description:  This file
 *
 *        Version:  1.0.0(29/01/19)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "29/01/19 15:34:41"
 *
 ********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <getopt.h>
#include <libgen.h>
#include <string.h>
#include <errno.h>
 
#include "logger.h"
#include "ds18b20.h"
#include "proc.h"
#include "packet.h"
#include "socket.h"
#include "database.h"
 
#define PROG_VERSION               "v1.0.0"
#define DAEMON_PIDFILE             "/tmp/.socketd.pid"
 
static void print_usage(char *progname)
{
    printf("Usage: %s [OPTION]...\n", progname);
    printf(" %s is LingYun studio temperature socket client program running on RaspberryPi\n", progname);
 
    printf("\nMandatory arguments to long options are mandatory for short options too:\n");
    printf("-i(ipaddr)    : sepcify server IP address\n");
    printf("-p(--port)    : sepcify server port.\n");
    printf("-I(--interval): sepcify report time interval, default 60 seconds\n");
    printf("-d(--debug)   : running in debug mode\n");
    printf("-h(--help)    : display this help information\n");
    printf("-v(--version) : display the program version\n");
 
    printf("\n%s version %s\n", progname, PROG_VERSION);
    return;
}
 
int check_sample_time(time_t *last_time, int interval);
 
int main (int argc, char **argv)
{
    int                daemon = 1;
    int                rv;
 
    char              *progname=NULL;
    char              *logfile="sock_client.log";
    int                loglevel=LOG_LEVEL_INFO;
    int                logsize=10; /* logfile size max to 10K */
 
    char              *serverip = NULL;
    int                port = 0;
    int                interval = 60; /* default report termperature every 60 seconds */
 
    socket_ctx_t         sock;
    time_t               last_time = 0;
    int                  sample_flag = 0;
 
    char                 pack_buf[1024];
    int                  pack_bytes = 0;
    pack_info_t          pack_info;
    pack_proc_t          pack_proc = packet_segmented_pack; /* use segmented string packet */
  //pack_proc_t          pack_proc = packet_json_pack;      /* use JSON string packet */
  //pack_proc_t          pack_proc = packet_tlv_pack;       /* use TLV(Tag Length Value) packet */
 
    struct option opts[] = {
        {"ipaddr", required_argument, NULL, 'i'},
        {"port", required_argument, NULL, 'p'},
        {"interval", required_argument, NULL, 'I'},
        {"debug", no_argument, NULL, 'd'},
        {"version", no_argument, NULL, 'v'},
        {"help", no_argument, NULL, 'h'},
        {NULL, 0, NULL, 0}
    };
 
    progname = (char *)basename(argv[0]);
 
    /* Parser the command line parameters */
    while( (rv=getopt_long(argc, argv, "i:p:I:dvh", opts, NULL)) != -1 )
    {
        switch (rv)
        {
            case 'i': /* set socket server hostname or IP address */
                serverip=optarg;
                break;
 
            case 'p': /* set socket server listen port */
                port=atoi(optarg);
                break;
 
            case 'I': /* set report time interval */
                interval=atoi(optarg);
                break;
 
 
            case 'd': /* set debug running */
                daemon = 0;
                logfile="console";
                loglevel=LOG_LEVEL_DEBUG;
                break;
 
            case 'v':  /* get software version */
                printf("%s version %s\n", progname, PROG_VERSION);
                return 0;
 
            case 'h':  /* get help information */
                print_usage(progname);
                return 0;
 
            default:
                break;
        }
 
    }
 
    if( !serverip || !port )
    {
        print_usage(argv[0]);
        return 0;
    }
 
    if( log_open(logfile, loglevel, logsize, THREAD_LOCK_NONE) < 0 )
    {
        fprintf(stderr, "Initial log system failed\n");
        return 1;
    }
 
    install_default_signal();
 
    if( check_set_program_running(daemon, DAEMON_PIDFILE) < 0 )
        goto cleanup;
 
    log_info("program start running.\n");
 
    if( database_init("sock_client.db") < 0 )
    {
        return 2;
    }
 
    socket_init(&sock, serverip, port);
 
    while( ! g_signal.stop )
    {
        /* +----------------------------------+
         * |  check and sample temperature    |
         * +----------------------------------+*/
 
        sample_flag = 0; /* clear sample flag */
 
        if( check_sample_time(&last_time, interval) )
        {
            log_debug("start DS18B20 sample termperature\n");
 
            if( (rv=ds18b20_get_temperature(&pack_info.temper)) < 0 )
            {
                log_error("DS18B20 sample temperature failure, rv=%d\n", rv);
                continue;
            }
            log_info("DS18B20 sample termperature %.3f oC\n", pack_info.temper);
 
            get_devid(pack_info.devid, sizeof(pack_info.devid), 88);
            get_time(&pack_info.sample_time);
 
            pack_bytes = pack_proc(&pack_info, (uint8_t *)pack_buf, sizeof(pack_buf));
            log_dump(LOG_LEVEL_DEBUG, NULL, pack_buf, pack_bytes);
 
            sample_flag = 1; /* set sample flag */
        }
 
        /* +---------------------------------+
         * |  check and do socket connect    |
         * +---------------------------------+*/
 
        /* start connect to server if not connected */
        if( !socket_connected(&sock) )
        {
            socket_connect(&sock);
        }
 
        /* +-------------------------------+
         * |      socket disconnect        |
         * +-------------------------------+*/
        if( !socket_connected(&sock) )
        {
            if( sample_flag )
            {
                database_push_packet(pack_buf, pack_bytes);
            }
 
            continue;
        }
 
        /* +-------------------------------+
         * |      socket connected         |
         * +-------------------------------+*/
 
        /*  socket send sample packet */
        if( sample_flag )
        {
            log_debug("socket send sample packet bytes[%d]: %s\n", pack_bytes, pack_buf);
            if( socket_send(&sock, pack_buf, pack_bytes) < 0 )
            {
                log_warn("socket send sample packet failure, save it in database now.\n");
                database_push_packet(pack_buf, pack_bytes);
                continue;
            }
        }
 
        /*  socket send packet in database  */
        if( !database_pop_packet(pack_buf, sizeof(pack_buf), &pack_bytes) )
        {
            log_debug("socket send database packet bytes[%d]: %s\n", pack_bytes, pack_buf);
            if( socket_send(&sock, pack_buf, pack_bytes) < 0 )
            {
                log_error("socket send database packet failure");
                continue;
            }
            else
            {
                log_warn("socket send database packet okay, remove it from database now.\n");
                database_del_packet();
            }
        }
 
        msleep(5);
    }
 
cleanup:
    socket_term(&sock);
    database_term();
    unlink(DAEMON_PIDFILE);
    log_close();
 
    return 0;
}
 
int check_sample_time(time_t *last_time, int interval)
{
    int                  need = 0; /* no need sample now */
    time_t               now;
 
    time(&now);
 
    if( difftime(now, *last_time)>interval )
    {
        need = 1; /* need sample now  */
        *last_time = now;
    }
 
    return need;
}

